package com.biz.primus.ms.commodity.service.backend;

import com.biz.primus.base.enums.ChannelType;
import com.biz.primus.base.enums.CommonStatus;
import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.commodity.enums.ProductType;
import com.biz.primus.commodity.exception.CommodityExceptionType;
import com.biz.primus.commodity.vo.TypeAProductModifyEventVo;
import com.biz.primus.commodity.vo.TypeBProductModifyEventVo;
import com.biz.primus.commodity.vo.evaluation.backend.EvaluationAuditRequestVo;
import com.biz.primus.commodity.vo.evaluation.backend.EvaluationDetailVo;
import com.biz.primus.commodity.vo.evaluation.backend.EvaluationQueryRequestVo;
import com.biz.primus.commodity.vo.evaluation.backend.EvaluationResponseVo;
import com.biz.primus.commodity.vo.evaluation.frontend.VendorIdPageRequestVo;
import com.biz.primus.commodity.vo.unused.MemberIdRequestVo;
import com.biz.primus.commodity.vo.unused.UserResponseVo;
import com.biz.primus.common.utils.DateUtil;
import com.biz.primus.common.utils.ValueUtils;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.model.vendor.vo.VendorVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.commodity.dao.po.Evaluation;
import com.biz.primus.ms.commodity.dao.po.Product;
import com.biz.primus.ms.commodity.dao.po.ProductStatistic;
import com.biz.primus.ms.commodity.dao.redis.EvaluationRedisDao;
import com.biz.primus.ms.commodity.dao.repository.evaluation.EvaluationRepository;
import com.biz.primus.ms.commodity.dao.repository.product.ProductRepository;
import com.biz.primus.ms.commodity.dao.repository.productstatistic.ProductStatisticRepository;
import com.biz.primus.ms.commodity.dao.ro.EvaluationRo;
import com.biz.primus.ms.commodity.dao.specification.EvaluationSpecification;
import com.biz.primus.ms.commodity.event.TypeAProductModifyEvent;
import com.biz.primus.ms.commodity.event.TypeBProductModifyEvent;
import com.biz.primus.ms.commodity.feign.UserFeignClient;
import com.biz.primus.ms.commodity.feign.VendorFeignClient;
import com.biz.primus.ms.commodity.trans.Evaluation2EvaluationDetailVo;
import com.biz.primus.ms.commodity.trans.Evaluation2EvaluationResponseVo;
import com.biz.primus.ms.commodity.trans.Evaluation2EvaluationRo;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 评论serviceImpl
 *
 * @author yangzichun
 * @date 2017/2/8
 */
@Slf4j
@Service
public class EvaluationBackendService extends AbstractBaseService {

    private static final int MAX_SCORE = 50; //店铺最高评分

    @Autowired
    private EvaluationRepository evaluationRepository;

    @Autowired
    private EvaluationRedisDao evaluationRedisDao;

    @Autowired
    protected UserFeignClient userService;

    @Autowired
    private VendorFeignClient vendorBackendService;

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private ProductStatisticRepository productStatisticRepository;
    /**
     * 根据分页请求分页查询评价 vo
     *
     * @param reqVo 分页请求 vo
     * @return 评价分页结果
     */
    public SpringPageVO<EvaluationResponseVo> findEvaluations(EvaluationQueryRequestVo reqVo) {
        PageRequest pageRequest = new PageRequest(reqVo.getPage(), reqVo.getSize());
        //根据参数查询
        Page<Evaluation> page = evaluationRepository.findAll(new EvaluationSpecification(reqVo), pageRequest);
        if (page == null) {
            return new SpringPageVO<EvaluationResponseVo>(Lists.<EvaluationResponseVo>newArrayList(), (long) reqVo.getPage(), reqVo.getSize(), 0);
        }
        return new SpringPageVO<EvaluationResponseVo>( Lists.transform(page.getContent(), new Evaluation2EvaluationResponseVo()),
                page.getTotalElements(),page.getSize(),reqVo.getPage());
    }

    public EvaluationDetailVo findEvaluation(Long id) {
        Evaluation evaluation = evaluationRepository.findOne(id);
        UserResponseVo userResponseVo = userService.findByMemberId(evaluation.getMemberId());
        EvaluationDetailVo evaluationDetailVo = new Evaluation2EvaluationDetailVo().apply(evaluation);
        Preconditions.checkArgument(evaluationDetailVo != null);
        evaluationDetailVo.setAccountName(userResponseVo == null ? null : userResponseVo.getAccountName());
        evaluationDetailVo.setCommonStatus(evaluation.getCommonStatus().getValue() + "");
        return evaluationDetailVo;
    }

    @Transactional
    public void auditEvaluation(EvaluationAuditRequestVo reqVo) {
        //判断参数异常
        Evaluation evaluation = evaluationRepository.findOne(reqVo.getId());
        AssertUtils.notNull(evaluation, CommodityExceptionType.COMMON_EXCEPTION,"未找到评论");
        //修改评价po审核状态
        evaluation.setCommonStatus(reqVo.getStatus() != null ? reqVo.getStatus() : CommonStatus.DISABLE);
        EvaluationRo evaluationRo = null;
        if (evaluation.getCommonStatus() == CommonStatus.ENABLE) { //评论审核通过
            MemberIdRequestVo memberIdRequestVo = new MemberIdRequestVo();
            memberIdRequestVo.setMemberId(evaluation.getMemberId());
            memberIdRequestVo.setChannelCode(ChannelType.BBC.getCode());
            UserResponseVo userResponseVo = userService.findByMemberIdCondition(memberIdRequestVo);
            evaluationRo = new Evaluation2EvaluationRo().apply(evaluation);
            Preconditions.checkArgument(evaluationRo != null);
            if(userResponseVo != null) {
                evaluationRo.setAccountName(userResponseVo.getAccountName());
            }
            evaluationRo.setUpdateTimestamp(DateUtil.now());
            //计算商品评价
            Product product = evaluation.getProduct();
            ProductStatistic productStatistic = productStatisticRepository.findByProductId(product.getId());
            if(productStatistic == null){
                log.info("评价商品{} 无stastic 初始化",product.getProductCode());
                productStatistic = new ProductStatistic();
                productStatistic.setProduct(product);
                productStatistic.setId(idService.getNextId());
            }
            productStatistic.setEvaluationCount(ValueUtils.getValue(productStatistic.getEvaluationCount()) + 1);
            Integer productScore = Math.min(ValueUtils.getValue(evaluation.getAttitudeScore()), MAX_SCORE);
            Double totalScore = new Double(Math.min(ValueUtils.getValue(evaluation.getAttitudeScore()), MAX_SCORE) +
                    Math.min(ValueUtils.getValue(evaluation.getDescriptionScore()), MAX_SCORE) +
                    Math.min(ValueUtils.getValue(evaluation.getLogisticsScore()), MAX_SCORE));
            Integer newAverageScore = Long.valueOf(Math.round(totalScore / new Double(3))).intValue();
            productStatistic.setProductScore((newAverageScore + productScore) / 2);
            product.setProductStatistic(productStatistic);
            productStatistic.setLogisticsScore(evaluation.getLogisticsScore());
            productRepository.save(product);
            if(ProductType.TYPE_B.equals(product.getProductType())){
                TypeBProductModifyEventVo typeBProductModifyEventVo = new TypeBProductModifyEventVo();
                typeBProductModifyEventVo.setProductId(product.getId());
                publishEvent(new TypeBProductModifyEvent(this, typeBProductModifyEventVo));
            }else {
                TypeAProductModifyEventVo typeAProductModifyEventVo = new TypeAProductModifyEventVo();
                typeAProductModifyEventVo.setProductId(product.getId());
                publishEvent(new TypeAProductModifyEvent(this, typeAProductModifyEventVo));
            }
            evaluationRepository.save(evaluation);
        }
        final Long id = evaluation.getId();
        final EvaluationRo finalEvaluationRo = evaluationRo;
        this.delayer.executeAfterTransactionCommit(()->{
            if (finalEvaluationRo != null) {
                evaluationRedisDao.save(finalEvaluationRo);
            } else {
                evaluationRedisDao.delete(id);
            }
        });
        evaluationRepository.save(evaluation);
    }

    public void statVendorScore() {
        //获取全部的店铺
            List<VendorVo> vendorVos = vendorBackendService.findAll();
            if (CollectionUtils.isNotEmpty(vendorVos)) {
                for (VendorVo vendorVo : vendorVos) {
                    try {
                        this.statVendorScore(vendorVo);
                    } catch (Exception e) {
                        log.error("统计店铺[id={}, name={}]评分异常", vendorVo.getId(), vendorVo.getVendorName());
                    }
                }
            }
            log.debug("完成统计店铺评分");
    }

    private void statVendorScore(VendorVo vendorVo) {
        log.debug("统计店铺[id={}, name={}]评分", vendorVo.getId(), vendorVo.getVendorName());
        //根据vendorId查询该店铺下全部的通过审核的评价
        VendorIdPageRequestVo reqVo = new VendorIdPageRequestVo();
        reqVo.setVendorId(Long.valueOf(vendorVo.getId()));
        List<EvaluationRo> evaluationRos = evaluationRedisDao.findAllByVendorId(Long.valueOf(vendorVo.getId()));
        if (CollectionUtils.isEmpty(evaluationRos)) {
            return;
        }
        //计算总分
        Integer attitudeSum = 0;
        Integer attitudeNum = 0;
        Integer logisticsSum = 0;
        Integer logisticsNum = 0;
        Integer descriptionSum = 0;
        Integer descriptionNum = 0;
        for (EvaluationRo evaluationRo : evaluationRos) {
            if (evaluationRo.getAtitudeScore() != null) {
                attitudeSum += Math.min(ValueUtils.getValue(evaluationRo.getAtitudeScore()), MAX_SCORE);
                attitudeNum++;
            }
            if (evaluationRo.getLogisticsScore() != null) {
                logisticsSum += Math.min(ValueUtils.getValue(evaluationRo.getLogisticsScore()), MAX_SCORE);
                logisticsNum++;
            }
            if (evaluationRo.getDescriptionScore() != null) {
                descriptionSum += Math.min(ValueUtils.getValue(evaluationRo.getDescriptionScore()), MAX_SCORE);
                descriptionNum++;
            }
        }
        //计算平均得分(由于订单评分设计是10总分（最小单位0.5），店铺评分是50总分（最小单位0.1）)
        Integer attitudeScore = attitudeSum  / evaluationRos.size();
        Integer logisticsScore = logisticsSum / evaluationRos.size();
        Integer descriptionScore = descriptionSum  / evaluationRos.size();
        //如果数据库中没有该店铺的评分，分配新的id  todo:nan
//        vendorVo.setAttitudeScore(attitudeScore);
//        vendorVo.setAttitudeNum(attitudeNum);
//        vendorVo.setLogisticsScore(logisticsScore);
//        vendorVo.setLogisticsNum(logisticsNum);
//        vendorVo.setDescriptionScore(descriptionScore);
//        vendorVo.setDescriptionNum(descriptionNum);
        vendorBackendService.updateVendorScore(vendorVo);
    }
}
